/*******************************************************************************
 * Copyright 2011 Danny Kunz
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/
package org.omnaest.maven.plugin.technology_timeline;

import java.io.File;
import java.io.FileWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.codehaus.plexus.util.FileUtils;

/**
 * The {@link TimeLineMojo} extracts the {@link Calendar} information of the root files within the jar files of all dependency
 * artifacts. This information is written to a CSV file.
 * 
 * @goal timeline
 */
public class TimeLineMojo extends AbstractMojo
{
  /* ********************************************** Beans / Services ********************************************** */
  /** @parameter default-value="${project}" */
  private org.apache.maven.project.MavenProject               mavenProject;
  
  /** @component */
  private org.apache.maven.artifact.resolver.ArtifactResolver artifactResolver;
  
  /* ********************************************** Methods ********************************************** */
  
  /**
   * 
   */
  public void execute() throws MojoExecutionException
  {
    //
    this.getLog().info( "Starting technology timeline analysis" );
    
    //
    this.mavenProject.getBasedir();
    String directoryString = this.mavenProject.getBuild().getDirectory();
    File directory = new File( directoryString );
    File reportFile = new File( directory, "technology-timeline.csv" );
    
    //
    if ( !directory.exists() )
    {
      FileUtils.mkdir( directoryString );
    }
    
    //
    try
    {
      //      
      FileWriter reportFileWriter = new FileWriter( reportFile );
      reportFileWriter.write( "artifactId;date\n" );
      
      //
      this.getLog().info( "Report file: " + reportFile.getAbsolutePath() );
      
      //
      Set<Artifact> artifactSet = this.determineArtifactSet();
      if ( artifactSet != null )
      {
        //
        this.getLog().info( "Found " + artifactSet.size() + " dependencies" );
        
        //
        class ArtifactIdAndCalendar
        {
          public String   artifactId = null;
          public Calendar calendar   = null;
        }
        
        //
        List<ArtifactIdAndCalendar> artifactIdAndCalendarList = new ArrayList<ArtifactIdAndCalendar>();
        
        //
        for ( Artifact artifact : artifactSet )
        {
          //
          this.getLog().info( "Artifact: " + artifact.getId() );
          
          //
          {
            //
            this.getLog().debug( "        : locating the artifact file" );
            
            //
            File artifactFile = artifact.getFile();
            
            //
            if ( artifactFile != null )
            {
              //    
              this.getLog().debug( "   File : " + artifactFile.getAbsolutePath() );
              
              //
              Calendar calendar = ZipFileScanner.resolveLastFileCreationDateOfTopLevelFilesWithinZipFile( artifactFile );
              
              //    
              this.getLog().debug( "   Date : " + String.format( "%tc", calendar ) );
              
              //
              if ( calendar != null )
              {
                ArtifactIdAndCalendar artifactIdAndCalendar = new ArtifactIdAndCalendar();
                artifactIdAndCalendar.artifactId = artifact.getId();
                artifactIdAndCalendar.calendar = calendar;
                artifactIdAndCalendarList.add( artifactIdAndCalendar );
              }
            }
            else
            {
              //    
              this.getLog().debug( "   File : not available" );
            }
          }
        }
        
        //
        this.getLog().debug( "Writing report for " + artifactIdAndCalendarList.size() + " artifacts" );
        Collections.sort( artifactIdAndCalendarList, new Comparator<ArtifactIdAndCalendar>()
        {
          @Override
          public int compare( ArtifactIdAndCalendar artifactIdAndCalendar1, ArtifactIdAndCalendar artifactIdAndCalendar2 )
          {
            return artifactIdAndCalendar1.calendar.compareTo( artifactIdAndCalendar2.calendar );
          }
        } );
        for ( ArtifactIdAndCalendar artifactIdAndCalendar : artifactIdAndCalendarList )
        {
          //
          reportFileWriter.write( artifactIdAndCalendar.artifactId + ";"
                                  + new SimpleDateFormat( "yyyy-MM-dd" ).format( artifactIdAndCalendar.calendar.getTime() )
                                  + "\n" );
        }
      }
      
      //
      reportFileWriter.close();
    }
    catch ( Exception e )
    {
      e.printStackTrace();
    }
  }
  
  /**
   * @return
   */
  protected Set<Artifact> determineArtifactSet()
  {
    //    
    Set<Artifact> retset = new HashSet<Artifact>();
    
    //
    @SuppressWarnings("unchecked")
    Set<Artifact> artifactSet = this.mavenProject.getDependencyArtifacts();
    if ( artifactSet != null )
    {
      for ( Artifact artifact : artifactSet )
      {
        //
        ArtifactResolutionRequest request = new ArtifactResolutionRequest();
        request.setArtifact( artifact );
        this.artifactResolver.resolve( request );
        
        //
        retset.add( artifact );
      }
    }
    
    //
    return retset;
  }
}
